home *** CD-ROM | disk | FTP | other *** search
Wrap
Text File | 1992-09-03 | 6.6 KB | 195 lines | [ TEXT/NCII]
########## # Fourier Transforms # # function FFT(Cx) # Returns the discrete fourier transform of Cx. # function InvFFT(Ck) # Returns inverse discrete fourier transform. # # function SwapSides(V) # Returns array V with left and right halfs swapped. # # # With i=sqrt(-1), the transform is # # Cx=InvFFT(Cq) # (Sign= +1 transform) : # Cx[q] = Sum p=0…N-1 { exp( +i 2π p q/N ) Ck[p] } # Cq=FFT(Cx) # (Sign= -1 transform) : # Ck[p] =(1/N) Sum q=0…N-1 { exp( -i 2π p q/N ) Cx[q] } # # which has the normalization # (1/N) sum( |Cx|^2 ) = sum( |Ck|^2 ). # # # This text file explains and gives examples of # some of the routines in the file All Library Routines, which # should be Opened before trying any of these examples. # ########## ######### # Here is the xCOD: xfft # xCO2 xFFT(zN, Sign:real; cmplxData:ComplexArray; Error:real) , does a 1D Fast Fourier Transform on cmplxData[1..N]. zN must be a power of 2, else Error will be set to -1.; an external program. ################# # Interface files: # function FFT(Cx) # Returns the discrete fourier transform of Cx. . var n, Ck, err . # Input: Cx = real or complex array, 2^N points. . # Output: FFT = complex array = discrete fourier transform of Cx. . begin . Ck = Cx . n = size(Ck) . xFFT(n,-1,Ck,Err) . if Err<>0 then . begin . print(" •• ERROR in xFFT, err="+Err) . FFT = 0/0 # which is "Not a number" . end . else . FFT = Ck . end . function InvFFT(Ck) # Returns inverse discrete fourier transform. . var n, Cx, err . # Input: Ck = real or complex 2^N array . # Output: InvFFT = inverse discrete fourier transform, a complex array. . begin . Cx = Ck . n = size(Cx) . xFFT(n,1,Cx,Err) . if Err<>0 then . begin . print(" •• ERROR in xFFT, err="+Err) . invFFT = 0/0 # which is "Not a number" . end . else . InvFFT = Cx . end . # # The indeces are cyclic in the discrete fourier transform, with # Ck[N] the same as Ck[0]. FFT expects the "0 frequency" channel to # be the first number in the Ck array, which means that # the data is stored in the order # Ck[0], Ck[1], Ck[2],... , Ck[N-1]. # Because of the periodicity, Ck[N-1] is the same what would be # Ck[-1]; therefore, if its often convenient to plot Ck and Cx in the # order Ck[N/2], Ck[N/2+1],... ,Ck[N-1], Ck[0], Ck[1],.. Ck[N/2 -1] # which puts 0 in the middle. # Here's a routine to swap the two sides of an array, so that # the x=0 or k=0 channel will be in the middle when we plot it. # SwapSides(V) exchanges the left and right halves of a vector V. # Evaluate this by selecting it (or putting the cursor at the last # period) and hitting enter. # function SwapSides(V) # Returns array V with left and right halfs swapped. . var n, n0, SS, left,right . # Input: V[1…N] . # Output: SwapSides = { V[N/2], V[N/2+1], …, V[1],V[2,],…,V[N/2-1] } . begin . n = Size(V); # the length of V . n0 = FirstIndex(V); # V is V[n0...n0+n-1] . SS = V # save space for answer . left = n0…(n0+n/2+1) # left half indeces . right = (n0+n/2)…(n0+n-1) # right half indeces . SS[left] = V[right] . SS[right] = V[left] . SwapSides = SS # return the answer . end . ########### # Example: # N = 128; # the number of points in the arrays. Cx[0…N-1] = 0; # initialize the array. x = 0 … N-1; # initialize the x co-ords of the array. xSwap = -N/2 … N/2-1; # x co-ords of the "swapped" array. # Here's a "hatbox" , with C=1 for |x|<=4. Cx[0] = 1; Cx[1…4] = 1; Cx[N-4 … N-1] = 1; # To see this, plot [xSwap, SwapSides(Cx)] # Finally, do the transform. Ck = FFT(Cx) # <<<<<<<<<<<< This does the actual transform. # Several things went on there behind the scenes. # First, Err didn't exist when xFFT was called, so it was created # as a single real number. Err Err = 0 # Second, Ck was a real array when passed to xFFT, but xFFT # expected a complex array. (See the argument list returned # when FFT was evaluated.) So, Ck was converted to a complex # array (with 0's for the complex part), transformed, and returned. # Although you usually won't need to tell if an array is real or # complex (and in fact NCII will at times convert it back and forth # like this if it needs to and the the imaginary part is zero), you can # tell how big an array really is by using Size and SizeAsIfReal, # which aren't the same if the array or number is complex. # If you really want to see when something's complex, # here's a function that will beep when it is.. program BeepIfComplex(z) # beeps if Z is complex. . begin . if Size(z) <> SizeAsIfReal(z) then beep . end . # BeepIfComplex(Cx) # This won't beep when evaluated without the "#". # BeepIfComplex(Ck) # This will. # To see the transformed array, plot [xSwap, SwapSides(Ck)] . # This plots the real part of Ck. To see the imaginary part, you could # plot [xSwap, SwapSides(Imaginary(Ck))] ; # but since Cx is symmetric, the imaginary part is zero # (except for numerical errors), so this is boring in this case. maximum(| Imaginary(Ck) |) 2.8649365e-16 # Here is the check of the normalization: sum( |Ck|^2 ) 0.0703125 1/N sum( |Cx|^2 ) 0.0703125 # And finally, here's a table of some of the values. Note that these # have not been hit with SwapSides, so x=0 is the first number. # Table formats imaginary quantities as two colums of reals, # so the last two columns are both Ck. # # The actual table command is commented so that it won't do # anything if this whole file is evaluated. Just select it and hit # enter to make the table. # j = 0…12; Table(j, Cx[j],Ck[j]) # # x Cx Ck # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0 1 0.07031 0 1 1 0.06975 -5.455e-17 2 1 0.06807 -5.3077e-17 3 1 0.06534 -1.0133e-16 4 1 0.06161 -4.7384e-17 5 0 0.05701 -8.6654e-17 6 0 0.05165 -7.7217e-17 7 0 0.04568 -1.0006e-16 8 0 0.03928 -2.7712e-17 9 0 0.0326 -4.366e-17 10 0 0.02583 -3.173e-17 11 0 0.01913 -2.9912e-17 12 0 0.01269 -8.5849e-18